package com.redijedi.tapestry5.internal;

import java.util.Map;

import org.apache.tapestry.MarkupWriter;
import org.apache.tapestry.ValueEncoder;

import com.redijedi.tapestry5.TreeModelRenderer;
import com.redijedi.tapestry5.TreeNodeModel;

/**
 * @author torr
 * 
 */
public class TreeModelRendererImpl implements TreeModelRenderer {

	private final MarkupWriter _writer;

	@SuppressWarnings("all")
	private final ValueEncoder _encoder;

	public TreeModelRendererImpl(MarkupWriter writer) {
		_writer = writer;
		_encoder = null;
	}

	@SuppressWarnings("all")
	public TreeModelRendererImpl(MarkupWriter writer, ValueEncoder encoder) {
		_writer = writer;
		_encoder = encoder;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.redijedi.tapestry5.internal.TreeModelRenderer#preRender(com.redijedi.tapestry5.TreeNodeModel)
	 */
	public void preRender(TreeNodeModel treeNodeModel) {
		if (treeNodeModel == null) return;
		TreeNodeModelWrapper node = wrappedModel(treeNodeModel);
		render(node, node.getPreRenderAction());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.redijedi.tapestry5.internal.TreeModelRenderer#postRender(com.redijedi.tapestry5.TreeNodeModel)
	 */
	public void postRender(TreeNodeModel treeNodeModel) {
		if (treeNodeModel == null) return;
		TreeNodeModelWrapper node = wrappedModel(treeNodeModel);
		render(node, node.getPostRenderAction());
	}

	private TreeNodeModelWrapper wrappedModel(TreeNodeModel treeNodeModel) {
		TreeNodeModelWrapper node;
		if (treeNodeModel instanceof TreeNodeModelWrapper) {
			node = (TreeNodeModelWrapper) treeNodeModel;
		} else {
			node = new TreeNodeModelWrapper(treeNodeModel);
		}
		return node;
	}

	private void render(TreeNodeModel node, TreeRenderAction action) {
		switch (action) {
		case OPEN_CONTAINER:
			beginContainer(node);
			break;
		case OPEN_LIST:
			beginList(node);
			break;
		case OPEN_ITEM:
			beginItem(node);
			break;
		case CLOSE_ITEM:
			endItem();
			break;
		case CLOSE_LIST:
			endList();
			break;
		case CLOSE_CONTAINER:
			endContainer();
			break;
		}

	}

	private void beginContainer(TreeNodeModel node) {
		if (node == null) {
			return;
		}
		_writer.element("div");
		if (node.getId() != null) {
			_writer.attributes("id", node.getId());
		}
		writeAttributes(node.getAttributes());
	}

	private void beginList(TreeNodeModel node) {
		if (node == null) {
			return;
		}
		_writer.element("ul");
	}

	private void beginItem(TreeNodeModel node) {
		if (node == null) {
			return;
		}
		String clientValue = getClientValue(node);
		String clazz = "node_";
		_writer.element("li", "id", clientValue, "class", clazz);
		writeAttributes(node.getAttributes());
	}

	private void endItem() {
		_writer.end();
	}

	private void endList() {
		_writer.end();
	}

	private void endContainer() {
		_writer.end();
	}

	private void writeAttributes(Map<String, String> attributes) {
		if (attributes == null) {
			return;
		}
		for (Map.Entry<String, String> e : attributes.entrySet()) {
			_writer.attributes(e.getKey(), e.getValue());
		}
	}

	@SuppressWarnings("unchecked")
	private String getClientValue(TreeNodeModel treeNodeModel) {
		if (treeNodeModel == null) {
			return "";
		}
		Object nodeValue = treeNodeModel.getValue();
		if (_encoder != null) {
			return _encoder.toClient(nodeValue);
		} else {
			return InternalUtils.convertStringToIdentifier(treeNodeModel
					.getId());
		}
	}

}
